<template>
  <div class="app">
    <div class="search">
      <span>
        时间：<el-date-picker
          v-model="sateValue"
          type="daterange"
          range-separator="至"
          clearable
          size="small"
          @change="selectTime"
          style="width: 300px"
          start-placeholder="开始日期"
          end-placeholder="结束日期"
      >
        </el-date-picker>
      </span>
      <span>
        姓名：<el-input
          size="small"
          style="width: 200px"
          v-model="commissionName"
          placeholder="请输入姓名"
          clearable
      ></el-input>
      </span>
      <span>
        店铺名称：<el-input
          size="small"
          style="width: 200px"
          v-model="storeName"
          placeholder="请输入店铺名称"
          clearable
      ></el-input>
      </span>
      <el-button
          size="small"
          type="primary"
          style="margin-left: 10px"
          @click="search"
      >搜索
      </el-button
      >
    </div>
    <div class="topAdd">
      <el-button
          type="primary"
          style="float: right; margin-bottom: 5px; margin-left: 15px"
          @click="downMaterialFeeNew"
      ><i class="el-icon-download"></i>按人员下载
      </el-button>
      <el-button
          type="primary"
          style="float: right; margin-bottom: 5px; margin-left: 15px"
          @click="downMaterialFee"
      ><i class="el-icon-download"></i>按店铺下载
      </el-button>
      <el-button
          type="primary"
          style="float: right; margin-bottom: 5px"
          @click="addMaterialFee"
      >新增材料订单
      </el-button
      >
      <el-table
          :data="feeData"
          border
          :span-method="objectSpanMethod"
          height="calc(100vh - 350px)"
          :cellStyle="{ textAlign: 'center', 'font-size': '12px' }"
          :headerCellStyle="{
          textAlign: 'center',
          fontWeight: 400,
          background: '#66b1ff',
          color: 'white',
        }"
      >
        <el-table-column prop="commissionName" label="人员"></el-table-column>
        <el-table-column prop="storeName" label="店铺名称"></el-table-column>
        <el-table-column prop="areaName" label="所属仓库"></el-table-column>
        <el-table-column prop="deliveryDate" label="时间"></el-table-column>
        <el-table-column prop="materialFee" label="单次提成"></el-table-column>
        <!--        <el-table-column label="总提成">-->
        <!--          <template slot-scope="scope">-->
        <!--            <span style="color: orangered">{{ (scope.row.totalCommissionFee).toFixed(2) }}</span>-->
        <!--          </template>-->
        <!--        </el-table-column>-->
        <el-table-column prop="remark" label="备注"></el-table-column>
        <el-table-column label="状态">
          <template slot-scope="scope">
            <span
                v-if="scope.row.isCancelCommission == 1"
                style="color: #e57373"
            >已取消提成</span
            >
            <span v-else>正常</span>
          </template>
        </el-table-column>
        <el-table-column label="操作">
          <template slot-scope="scope">
            <el-link
                @click="cancelFee(scope.row)"
                style="text-decoration: underline; color: #66b1ff"
            >取消提成
            </el-link
            >
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
          style="padding: 20px 0"
          align="right"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
          :current-page="currentPage"
          :page-sizes="[20, 30, 40, 50]"
          layout="total, sizes, prev, pager, next, jumper"
          :total="totalCount"
      >
      </el-pagination>
    </div>
    <el-dialog
        :visible.sync="addDialog"
        width="30%"
        title="添加材料提成"
        center
    >
      <div>
        <span>店铺名称：</span>
        <el-select
            filterable
            remote
            :remote-method="remoteMethod"
            value-key="orderId"
            clearable
            v-model="storeName"
            size="small"
            allow-create
            style="width: 300px"
            placeholder="请输入店铺名称"
        >
          <el-option
              v-for="item in saleNameList"
              :key="item.orderId"
              :label="item.storeName"
              :value="item.storeName"
          >
          </el-option>
        </el-select>
      </div>
      <div style="margin-top: 20px">
        <span>材料人员：</span>
        <el-select
            v-model="cl"
            multiple
            filterable
            style="width: 300px"
            size="small"
        >
          <el-option
              v-for="(item, i) in list"
              :label="item.userName"
              :value="item.userName"
              :key="i"
          >
          </el-option>
        </el-select>
      </div>
      <div style="margin-top: 20px">
        <span>所属仓库：</span>
        <el-select
            v-model="areaId"
            clearable
            placeholder="请按区域搜索"
            size="small"
            style="width: 300px"
        >
          <el-option
              v-for="item in areaData"
              :key="item.area"
              :label="item.areaName"
              :value="item.area"
          >
          </el-option>
        </el-select>
      </div>
      <div style="margin-top: 20px">
        <span>提成备注：</span>
        <el-input
            type="textarea"
            size="small"
            style="width: 300px"
            v-model="remark"
        ></el-input>
      </div>
      <span slot="footer">
        <el-button size="small" @click="addDialog = false">取消</el-button>

        <el-button
            size="small"
            type="primary"
            @click="comfirm"
            v-prevent-re-click
        >确认</el-button
        >
      </span>
    </el-dialog>
    <el-dialog :visible.sync="cancelDialog" width="30%" title="取消提成" center>
      <div style="margin-top: 20px">
        <span>取消原因：</span>
        <el-input
            type="textarea"
            size="small"
            style="width: 300px"
            v-model="reason"
        ></el-input>
      </div>
      <span slot="footer">
        <el-button size="small" @click="cancelDialog = false">取消</el-button>

        <el-button size="small" type="primary" @click="comfirmCancel"
        >确认</el-button
        >
      </span>
    </el-dialog>
  </div>
</template>

<script>
import * as XLSX from 'xlsx-js-style'
import dayjs from 'dayjs'

export default {
  name: 'materialFee',
  data() {
    return {
      feeData: [],
      saleNameList: [],
      addDialog: false,
      sateValue: '',
      areaId: '',
      cancelDialog: false,
      storeName: '',
      commissionName: '',
      remark: '',
      pageNumber: 1,
      currentPage: 1,
      pageSize: 20,
      totalCount: 0,
      reason: '',
      list: [],
      areaData: [],
      params: {},
      cl: [],
    }
  },
  created() {
    this.getData()
    this.areaList()
    this.$api.orderSelectInstallationUser({loginType: 4}).then((res) => {
      this.list = res
    })
  },
  methods: {
    areaList() {
      this.$api.areaLedgerAreaList().then((res) => {
        this.areaData = res
      })
    },
    handleSizeChange(val) {
      this.pageSize = val
      this.getData()
    },
    handleCurrentChange(val) {
      this.pageNumber = val
      this.getData()
    },
    selectTime(val) {
      if (val) {
        this.params.startTime = dayjs(val[0]).format('YYYY-MM-DD')
        this.params.endTime = dayjs(val[1]).format('YYYY-MM-DD')
      } else {
        this.params.startTime = ''
        this.params.endTime = ''
      }
    },
    getData() {
      const data = {
        ...this.params,
        commissionName: this.commissionName,
        pageNumber: this.pageNumber,
        storeName: this.storeName,
        pageSize: this.pageSize,
      }
      this.$api.orderGetMaterialCommissionNameList(data).then((res) => {
        //         // 先按 installers 排序，使相同的安装人员相邻
        //         const sortedData = res.data.sort((a, b) => a.commissionName.localeCompare(b.commissionName));
        // // 遍历数据并计算相同 installers 的 commissionFee 总和
        //         let totalCommissionMap = {};
        //         sortedData.forEach(item => {
        //           if (!totalCommissionMap[item.commissionName]) {
        //             totalCommissionMap[item.commissionName] = 0;
        //           }
        //           totalCommissionMap[item.commissionName] += item.material_fee;
        //         });
        //
        // // 将commissionFee添加到每个数据项
        //         const result = sortedData.map(item => ({
        //           ...item,
        //           totalCommissionFee: totalCommissionMap[item.commissionName]
        //         }));
        this.feeData = res.data
        this.totalCount = res.total
      })
    },
    search() {
      const data = {
        ...this.params,
        commissionName: this.commissionName,
        pageNumber:1,
        startTime: this.params.startTime,
        endTime: this.params.endTime,
        storeName: this.storeName,
        pageSize: this.pageSize,
      }
      this.$api.orderGetMaterialCommissionNameList(data).then((res) => {
        //         // 先按 installers 排序，使相同的安装人员相邻
        //         const sortedData = res.data.sort((a, b) => a.commissionName.localeCompare(b.commissionName));
        // // 遍历数据并计算相同 installers 的 commissionFee 总和
        //         let totalCommissionMap = {};
        //         sortedData.forEach(item => {
        //           if (!totalCommissionMap[item.commissionName]) {
        //             totalCommissionMap[item.commissionName] = 0;
        //           }
        //           totalCommissionMap[item.commissionName] += item.material_fee;
        //         });
        //
        // // 将commissionFee添加到每个数据项
        //         const result = sortedData.map(item => ({
        //           ...item,
        //           totalCommissionFee: totalCommissionMap[item.commissionName]
        //         }));
        this.feeData = res.data
        this.totalCount = res.total
      })
    },
    addMaterialFee() {
      this.addDialog = true
      this.storeName = ''
      this.cl = []
      this.remark = ''
      this.areaId = ''
    },
    remoteMethod(val) {
      if (val) {
        const params = {
          storeName: val,
        }
        this.$api.orderGetOrderInfoLikeName(params).then((res) => {
          this.saleNameList = res
        })
      }
    },
    comfirm() {
      const newArr = []
      this.cl.forEach((commissionName) => {
        newArr.push({
          commissionName,
          storeName: this.storeName,
          remark: this.remark,
          areaId: this.areaId,
        })
      })
      this.$api.orderAddMaterialCommissionName(newArr).then((res) => {
        if (res == 1) {
          this.$message.success('添加成功！')
          this.addDialog = false
          this.getData()
        }
      })
    },
    cancelFee(row) {
      this.cancelId = row.id
      this.cancelDialog = true
      this.reason = ''
    },
    comfirmCancel() {
      const data = {
        id: this.cancelId,
        cancelReason: this.reason,
      }
      this.$api.orderCancelMaterialCommission(data).then((res) => {
        if (res == 1) {
          this.$message.success('取消成功！')
          this.cancelDialog = false
          this.getData()
        }
      })
    },

    objectSpanMethod({row, column, rowIndex, columnIndex}) {
      let spanOneArr = []
      let concatOne = 0
      this.feeData.map((item, index) => {
        if (index === 0) {
          spanOneArr.push(1)
        } else {
          //合并第一列 installers
          if (item.commissionName === this.feeData[index - 1].commissionName) {
            spanOneArr[concatOne] += 1
            spanOneArr.push(0)
          } else {
            spanOneArr.push(1)
            concatOne = index
          }
        }
      })
      //合并第一列和第二列
      if (columnIndex === 0) {
        const _row = spanOneArr[rowIndex]
        const _col = _row > 0 ? 1 : 0
        return {
          rowspan: _row,
          colspan: _col,
        }
      }
    },
    // 25/8/24改版
    async downMaterialFeeNew() {
      const dataRes = await this.$api.orderGetMaterialCommissionSummary({
        pageSize: 10000,
        pageNumber: 1,
        ...this.params,
      })
      const data = dataRes.data
      console.log('[ data ] >', data)
      // 获取所有唯一的 commissionName 和 storeName
      const commissions = Array.from(
          new Set(data.map((item) => item.commissionName))
      )
      const stores = Array.from(new Set(data.map((item) => item.storeName)))

      const sheetData = []
      // 添加表头
      sheetData.push(['店铺名称', ...commissions])

      // 为每个 store 添加行
      stores.forEach((store) => {
        const row = [store]
        commissions.forEach((commission) => {
          const commissionData = data.find(
              (item) =>
                  item.storeName === store && item.commissionName === commission
          )
          row.push(commissionData ? commissionData.materialFee : 0) // 如果找不到该项，填充 0
        })
        sheetData.push(row)
      })

      // 创建工作表和工作簿
      const ws = XLSX.utils.aoa_to_sheet(sheetData)
      const wb = XLSX.utils.book_new()
      XLSX.utils.book_append_sheet(wb, ws, 'Sheet1')
      ws['!cols'] = [
        {wpx: 200}, // 第一列宽度（Store Name列）
        ...commissions.map(() => ({wpx: 80})), // 其余列宽度
      ]
      // 设置居中对齐
      const range = XLSX.utils.decode_range(ws['!ref']) // 获取工作表范围
      for (let R = range.s.r; R <= range.e.r; R++) {
        for (let C = range.s.c; C <= range.e.c; C++) {
          const cellAddress = {r: R, c: C} // 获取单元格地址
          const cell = ws[XLSX.utils.encode_cell(cellAddress)]
          if (cell) {
            cell.s = cell.s || {} // 初始化样式
            cell.s.alignment = {
              horizontal: 'center', // 水平居中
              vertical: 'center', // 垂直居中
            }
          }
        }
      }
      // 生成并下载 Excel 文件
      XLSX.writeFile(wb, '材料总提成表.xlsx')
    },
    mergeSameCells(ws, data, colIndex, startRow = 2) {
      let merges = ws["!merges"] || [];
      let prevValue = null;
      for (let row = startRow; row < data.length; row++) {
        const value = data[row][colIndex];
        if (value === prevValue) {
          // 扩展上一段合并范围
          merges[merges.length - 1].e.r = row;
        } else {
          prevValue = value;
          merges.push({
            s: {r: row, c: colIndex},
            e: {r: row, c: colIndex}
          });
        }
      }
      ws["!merges"] = merges;
    },

// 旧的
    async downMaterialFee() {
      // 1. 获取数据
      const resData = await this.$api.orderGetMaterialCommissionSummary({
        pageSize: 10000,
        pageNumber: 1,
        ...this.params,
      });

      if (!resData?.data?.length) {
        this.$message.warning("暂无数据导出");
        return;
      }
      const sortedData = resData.data.sort((a, b) => a.storeName.localeCompare(b.storeName));
      // 遍历数据并计算相同 storeName 的 commissionName 总和
      let totalCommissionMap = {};
      sortedData.forEach(item => {
        if (item.isCancelCommission != 0) {
          item.commissionFee = 0
        }
        if (!totalCommissionMap[item.storeName]) {
          totalCommissionMap[item.storeName] = 0;
        }
        totalCommissionMap[item.storeName] += item.materialFee;
      });
      // 将commissionFee添加到每个数据项
      const result = sortedData.map(item => ({
        ...item,
        totalCommissionFee: totalCommissionMap[item.storeName],
        isCancelCommissionStr: item.isCancelCommission === 0 ? "正常" : "已取消提成"
      }));
      result.sort((a, b) => (a.storeName || '').localeCompare(b.storeName || ''));
      // 3. 组装表格数据
      const header = ['店铺名称', '所属仓库', '该店总数', '分配人员', '单次费用', '状态'];
      const sheetData = [
        ['材料提成汇总'],
        header,
        ...result.map(el => [
          el.storeName,
          el.areaName,
          el.totalCommissionFee,
          el.commissionName,
          el.materialFee,
          el.isCancelCommissionStr
        ])
      ];
      // 4. 创建 Sheet
      const ws = XLSX.utils.aoa_to_sheet(sheetData);
// 设置第一列和第二列居中
      // 样式工具函数
      const setStyle = (cell, style) => {
        if (!ws[cell]) return;
        ws[cell].s = {...(ws[cell].s || {}), ...style};
      };

      // 标题行样式
      setStyle("A1", {
        alignment: {horizontal: "center"},
        font: {bold: true, color: {rgb: "000000"}},
        fill: {fgColor: {rgb: "FF6A00"}}
      });

      // 表头样式
      header.forEach((_, idx) => {
        const cell = String.fromCharCode(65 + idx) + "2"; // A2 ~ G2
        setStyle(cell, {
          alignment: {horizontal: "center"},
          font: {bold: true, color: {rgb: "000000"}},
          fill: {fgColor: {rgb: "3CB371"}}
        });
      });
      const range = XLSX.utils.decode_range(ws['!ref']) // 获取工作表范围
      for (let R = range.s.r; R <= range.e.r; R++) {
        for (let C = range.s.c; C <= range.e.c; C++) {
          const cellAddress = {r: R, c: C} // 获取单元格地址
          const cell = ws[XLSX.utils.encode_cell(cellAddress)]
          if (cell) {
            cell.s = cell.s || {} // 初始化样式
            cell.s.alignment = {
              horizontal: 'center', // 水平居中
              vertical: 'center', // 垂直居中
            }
          }
        }
      }

      // 列宽
      ws["!cols"] = Array(header.length).fill({wpx: 150});
      // 合并标题行
      ws["!merges"] = [{s: {r: 0, c: 0}, e: {r: 0, c: header.length - 1}}];
// 合并相同店铺名称（A列 = colIndex 0）
      this.mergeSameCells(ws, sheetData, 0);
      // this.mergeSameCells(ws, sheetData, 2);
      // 5. 生成工作簿
      const wb = XLSX.utils.book_new();
      XLSX.utils.book_append_sheet(wb, ws, "提成汇总");
      // 6. 导出下载
      this.downloadExcel(wb, "材料提成汇总.xlsx");
    },
    downloadExcel(wb, fileName) {
      const wbout = XLSX.write(wb, {bookType: "xlsx", type: "binary"});
      const s2ab = s => {
        const buf = new ArrayBuffer(s.length);
        const view = new Uint8Array(buf);
        for (let i = 0; i < s.length; i++) view[i] = s.charCodeAt(i) & 0xff;
        return buf;
      };
      const blob = new Blob([s2ab(wbout)], {type: "application/octet-stream"});
      const link = document.createElement("a");
      link.href = URL.createObjectURL(blob);
      link.download = fileName;
      document.body.appendChild(link);
      link.click();
      setTimeout(() => {
        URL.revokeObjectURL(link.href);
        document.body.removeChild(link);
      }, 100);
    },
    s2ab(s) {
      const buf = new ArrayBuffer(s.length);
      const view = new Uint8Array(buf);
      for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
      return buf;
    }
  },
}
</script>

<style scoped></style>
